package eval.experiment;

import com.google.inject.Injector;
import eval.deploy.IDeployGenerator;
import eval.engine.EmptyPlacement;
import eval.engine.IPlacement;
import eval.engine.IPlacementEngine;
import eval.engine.IplacementEngineFactory;
import eval.host.HostGenerator;
import eval.host.IHostManager;
import eval.utilities.configuration.ExperimentConfiguration;
import eval.results.IResultManager;
import eval.results.IResultsData;

/**
 * This class represent a single experiment
 * 
 * @author Nicolo' M. Calcavecchia <calcavecchia@elet.polimi.it>
 * @author Amit Peled   <amit.kapina@gmail.com>
 * @author Igal Kaufman <igal.kaufman@gmail.com>
 */
public class Experiment {


	private static ExperimentConfiguration configuration = ExperimentConfiguration.getSingleton();
	private IHostManager hostManager;
	private IPlacementEngine placementEngine;
	private IDeployGenerator deployManagerFiller;
	private IResultManager resultManager;

	/**
	 * @Constructor 
	 * @param injector 
	 */
	public Experiment(Injector injector) {

		//Injector interface
		this.hostManager = injector.getInstance(IHostManager.class);
		this.deployManagerFiller = injector	.getInstance(IDeployGenerator.class);
		this.resultManager = injector.getInstance(IResultManager.class);


		//Generate hosts
		HostGenerator hostGenerator = new HostGenerator(hostManager);
		hostManager.addHosts(hostGenerator.generateHosts(configuration.totalNumberOfHosts));
		hostManager.InitHostsInCloud();

		//Generate Demand
		deployManagerFiller.generateDeploys();

		//Generate engine
		IplacementEngineFactory placementFactory = injector.getInstance(IplacementEngineFactory.class);
		this.placementEngine = placementFactory.createNewEngine(configuration.optimizationGoal);


	}

	/**
	 * Runs the experiment over all ticks.
	 * 
	 * @param resFileName the name to the result
	 */
	public void runExperiment(String resFileName) {
		long experimentStartTime = System.currentTimeMillis();
		IPlacement lastPlacement = new EmptyPlacement();
		IPlacement newPlacement = new EmptyPlacement();

		for (int tick = 0; tick < configuration.experimentTicks ; tick++) {
			System.out.println("\n<-----  TICK ("
					+ tick
					+ ") ----->"
					);

			long tickStartTime = System.currentTimeMillis();
			newPlacement = placementEngine.computePlacement(tick,lastPlacement);////

			resultManager.setExecutionTimesAtTick(tickStartTime,
					placementEngine.getEngineTimeInSec(), tick);
			resultManager.addPlacementAtTick(newPlacement, tick);
			lastPlacement = newPlacement;
			System.gc();
			// end of tick
		}

		resultManager
		.addExperimentTotalTime((System.currentTimeMillis() - experimentStartTime) / 1000.0);

		//if needed run saintyCheck at the end of the experiment. 
		if(configuration.enableSaintyCheck){
			resultManager.performSaintyCheck(resFileName);
		}
	}

	/**
	 * Get the result
	 * @return ResultsData
	 */
	public IResultsData getResultsData() {
		return resultManager.getResultsData();
	}

}
